package cn.leedsoft.luma.plugins.memcached;

import net.spy.memcached.MemcachedClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@SuppressWarnings("unchecked")
@Component
public class MemcachedUtil {
    private final long updateTimeout = 2500;
    private final Logger logger = LoggerFactory.getLogger(MemcachedUtil.class);
    @Autowired
    private MemcachedClient memcachedClient;

    /**
     * Get方法, 转换结果类型并屏蔽异常, 仅返回Null.同步方法
     */
    public <T> T get(String key) {
        try {
            return (T) memcachedClient.get(key);
        } catch (RuntimeException e) {
            handleException(e, key);
            return null;
        }
    }

    /**
     * 异步Set方法, 不考虑执行结果.
     */
    public void set(String key, int expiredTime, Object value) {
        memcachedClient.set(key, expiredTime, value);
    }
    /**
     * 安全的Set方法, 保证在updateTimeout秒内返回执行结果, 否则返回false并取消操作.
     */
    public boolean safeSet(String key, int expiration, Object value) {
        Future<Boolean> future = memcachedClient.set(key, expiration, value);
        try {
            return future.get(updateTimeout, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            future.cancel(false);
        }
        return false;
    }

    /**
     * 异步 Delete方法, 不考虑执行结果.
     */
    public void delete(String key) {
        memcachedClient.delete(key);
    }

    /**
     * 安全的Delete方法, 保证在updateTimeout秒内返回执行结果, 否则返回false并取消操作.
     */
    public boolean safeDelete(String key) {
        Future<Boolean> future = memcachedClient.delete(key);
        try {
            return future.get(updateTimeout, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            future.cancel(false);
        }
        return false;
    }

    /**
     * Incr方法.内部实现是：enqueue。同步方法
     */
    public long incr(String key, int by) {
        return memcachedClient.incr(key, by);
    }
    /**
     * Decr方法.
     */
    public long decr(String key, int by) {
        return memcachedClient.decr(key, by);
    }

    /**
     * 异步Incr方法, 不支持默认值, 若key不存在返回-1.
     */
    public Future<Long> asyncIncr(String key, int by) {
        return memcachedClient.asyncIncr(key, by);
    }
    /**
     * 异步Decr方法, 不支持默认值, 若key不存在返回-1.
     */
    public Future<Long> asyncDecr(String key, int by) {
        return memcachedClient.asyncDecr(key, by);
    }

    private void handleException(Exception e, String key) {
        logger.error("spymemcached client get操作失败，对应key:" + key, e);
    }

    /**
     * @param key
     * @param expiredTime
     * @param callback
     * @param forceFlush  是否强制刷新缓存
     * @param <T>
     * @return
     */
    public <T> T getWhenNotExistThenSet(String key, int expiredTime, MemcachedCallBack<T> callback, boolean forceFlush) {
        T obj = null;
        if (forceFlush) {//强制刷新缓存，不读缓存返回最新内容
            obj = callback.getMemcachedObject();
            if (obj != null) {
                set(key, expiredTime, obj);
                logger.debug("强制刷新缓存，初始化缓存，key为：" + key);
            } else {
                logger.debug("强制刷新缓存，回调函数后，需缓存对象仍为null，key为：" + key);
                return null;
            }
            return obj;
        }

        obj = get(key);
        if (obj == null) {
            obj = callback.getMemcachedObject();
            if (obj != null) {
                set(key, expiredTime, obj);
                logger.debug("缓存未命中，初始化缓存，key为：" + key);
            } else {
                logger.debug("缓存未命中，回调函数后，需缓存对象仍为null，key为：" + key);
                return null;
            }
        } else {
            logger.debug("缓存命中，key为：" + key);
        }

        return obj;
    }

    public interface MemcachedCallBack<T> {
        T getMemcachedObject();
    }
}
